package com.gxa.security.service.impl;

import com.gxa.security.entity.Menu;
import com.gxa.security.entity.Role;
import com.gxa.security.entity.User;
import com.gxa.security.mapper.MenuMapper;
import com.gxa.security.mapper.RoleMapper;
import com.gxa.security.mapper.UserMapper;
import com.gxa.security.security.entity.SecurityUser;
import org.springframework.beans.BeanUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

//自定义UserDetailsService实例对象，改用自己定义的。

/**
 * Spring Security中进行身份验证的是AuthenticationManager接口，
 * ProviderManager是它的一个默认实现，但它并不用来处理身份认证，而是委托给配置好的AuthenticationProvider，
 * 每个AuthenticationProvider会轮流检查身份认证。检查后或者返回Authentication对象或者抛出异常。
 * 验证身份就是加载响应的UserDetails，看看是否和用户输入的账号、密码、权限等信息匹配。
 * 此步骤由实现AuthenticationProvider的DaoAuthenticationProvider（它利用UserDetailsService验证用户名、密码和授权）处理。
 * 包含 GrantedAuthority 的 UserDetails对象在构建 Authentication对象时填入数据。
 */
@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {

    @Resource
    private UserMapper userMapper;

    @Resource
    RoleMapper roleMapper;

    @Resource
    MenuMapper menuMapper;


    /**
     * 在认证调用这个方法 验证这个用户是否存在 如果存在就查询出他的角色信息 将角色信息返回给授权信息
     * @param username
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //根据用户查询用户权限列表
        User user = userMapper.findUserByUsername(username);

        //判断
        if(user == null) {
            throw new UsernameNotFoundException("用户不存在");
        }
//        ===================================================================================================
        //RBAC基于角色的权限控制
        //根据用户id查询对应角色信息
        Role role = roleMapper.findRoleByUserId(user.getRoleId());
        //根据账户id查询对应的角色
        //根据对应的角色id查询对应权限
        Set<String> sys_menuSets = new HashSet<>();
        List<Menu> menuList = menuMapper.findMenuListByRoleId(role.getId());

        for (Menu sm:menuList) {
//            权限名称
            sys_menuSets.add(sm.getMenuName());
        }
        //将查询的账户与权限塞给SecurityUser对象
        SecurityUser securityUser = new SecurityUser();
//        User loginUser = new User();
//        BeanUtils.copyProperties(loginUser,user);
        //塞对象
        securityUser.setCurrentUserInfo(user);
        //塞权限
        securityUser.setPermissionValueList(sys_menuSets);
        return securityUser;
    }
}
